package junior.sample.test.config;

import com.zaxxer.hikari.HikariDataSource;
import junior.db.dao.BaseMapperFactory;
import junior.db.dao.jdbc.JdbcDao;
import junior.db.dao.mybatis.interceptor.BaseMapperInterceptor;
import junior.db.dao.mybatis.mapper.EntityMapper;
import junior.db.dao.mybatis.type.PersistEnumTypeHandler;
import junior.db.mapping.AnnotationColumnMapping;
import junior.db.mapping.AnnotationTableMapping;
import junior.db.mapping.CamelCaseColumnMapping;
import junior.db.mapping.CamelCaseTableMapping;
import junior.db.mapping.ColumnMapping;
import junior.db.mapping.MappingProvider;
import junior.db.mapping.TableMapping;
import org.apache.ibatis.logging.slf4j.Slf4jImpl;
import org.apache.ibatis.plugin.Interceptor;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.core.env.Environment;

import javax.sql.DataSource;

/**
 * @author wubo
 * @date 2024/7/31 14:43
 */
@Configuration
@MapperScan(basePackages = {"junior.db.dao.mybatis.mapper", "junior.sample.test.demo.mapper"}, sqlSessionFactoryRef = "sqlSessionFactory")
public class DaoConfig {
    @Bean
    public TableMapping tableMapping() {
        return new AnnotationTableMapping(new CamelCaseTableMapping());
    }
    
    @Bean
    public ColumnMapping columnMapping() {
        CamelCaseColumnMapping columnMapping = new CamelCaseColumnMapping();
        columnMapping.setColumnPrefix("`");
        columnMapping.setColumnSuffix("`");
        return new AnnotationColumnMapping(tableMapping(), columnMapping);
    }

    @Bean
    public MappingProvider mappingProvider() {
        MappingProvider mappingProvider =  new MappingProvider();
        mappingProvider.setTableMapping(tableMapping());
        mappingProvider.setColumnMapping(columnMapping());
        return mappingProvider;
    }
    
    @Bean
    public DataSource dataSource(Environment env) {
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setJdbcUrl(env.getProperty("jdbc.url"));
        dataSource.setDriverClassName(env.getProperty("jdbc.driver"));
        dataSource.setUsername(env.getProperty("jdbc.username"));
        dataSource.setPassword(env.getProperty("jdbc.password"));
        return dataSource;
    }
    
    @DependsOn("mappingProvider")
    @Bean
    public JdbcDao jdbcDao(DataSource dataSource) {
        return new JdbcDao(dataSource);
    }
    
    @DependsOn("mappingProvider")
    @Bean
    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        
        bean.setTypeAliasesPackage("junior.sample.test.demo.model");
        
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setMapUnderscoreToCamelCase(true);
        configuration.setLogImpl(Slf4jImpl.class);
        configuration.setDefaultEnumTypeHandler(PersistEnumTypeHandler.class);
        bean.setConfiguration(configuration);
        
        bean.setPlugins(new Interceptor[]{
            new BaseMapperInterceptor()
        });
        
        return bean;
    }
    
    @DependsOn("sqlSessionFactory")
    public BaseMapperFactory baseMapperFactory(EntityMapper entityMapper) {
        return new BaseMapperFactory(entityMapper);
    }
    
}
